package com.lee.app.config;

import com.lee.app.util.DecryptUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Component;

import java.util.LinkedHashMap;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/**
 * 敏感信息的解密
 */
@Component
public class DecryptConfig implements EnvironmentAware, BeanFactoryPostProcessor {

    private static final Logger LOGGER = LoggerFactory.getLogger(DecryptConfig.class);

    private ConfigurableEnvironment environment;

    private String decryptPrefix = "Enc[";                      // 解密前缀标志 默认值
    private String decryptSuffix = "]";                         // 解密后缀标志 默认值
    private String decryptKey = "hello!@#$world";               // 解密可以 默认值

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = (ConfigurableEnvironment) environment;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        LOGGER.info("敏感信息解密开始.....");
        MutablePropertySources propSources = environment.getPropertySources();
        StreamSupport.stream(propSources.spliterator(), false)
                .filter(ps -> ps instanceof OriginTrackedMapPropertySource)
                .collect(Collectors.toList())
                .forEach(ps -> convertPropertySource((PropertySource<LinkedHashMap>) ps));
        LOGGER.info("敏感信息解密完成.....");
    }

    /**
     * 解密相关属性
     * @param ps
     */
    private void convertPropertySource(PropertySource<LinkedHashMap> ps) {
        LinkedHashMap source = ps.getSource();
        setDecryptProperties(source);
        source.forEach((k,v) -> {
            String value = String.valueOf(v);
            if (!value.startsWith(decryptPrefix) || !value.endsWith(decryptSuffix)) {
                return;
            }
            String cipherText = value.replace(decryptPrefix, "").replace(decryptSuffix, "");
            String clearText = DecryptUtil.aesDecrypt(cipherText, decryptKey);
            source.put(k, clearText);
        });
    }

    /**
     *  设置解密属性
     * @param source
     */
    private void setDecryptProperties(LinkedHashMap source) {
        decryptPrefix = source.get("decrypt.prefix") == null ? decryptPrefix : String.valueOf(source.get("decrypt.prefix"));
        decryptSuffix = source.get("decrypt.suffix") == null ? decryptSuffix : String.valueOf(source.get("decrypt.suffix"));
        decryptKey = source.get("decrypt.key") == null ? decryptKey : String.valueOf(source.get("decrypt.key"));
    }
}
